package com.ittao.taoaicodemother.ai;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.ittao.taoaicodemother.ai.guardrail.PromptSafetyInputGuardrail;
import com.ittao.taoaicodemother.ai.tools.ToolManager;
import com.ittao.taoaicodemother.config.VipLimitConfig;
import com.ittao.taoaicodemother.config.StreamingChatModelConfig;
import com.ittao.taoaicodemother.config.ReasoningStreamingChatModelConfig;
import com.ittao.taoaicodemother.model.entity.User;
import com.ittao.taoaicodemother.model.enums.CodeGenTypeEnum;
import com.ittao.taoaicodemother.service.ChatHistoryService;
import com.ittao.taoaicodemother.service.VipLimitService;
import com.ittao.taoaicodemother.utils.ApplicationContextProvider;
import dev.langchain4j.community.store.memory.chat.redis.RedisChatMemoryStore;
import dev.langchain4j.data.message.ToolExecutionResultMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

/**
 * AI 服务创建工厂
 */
@Configuration
@Slf4j
public class AiCodeGeneratorServiceFactory {

    @Resource
    private VipLimitConfig vipLimitConfig;

    @Resource(name = "openAiChatModel")
    private ChatModel chatModel;

    @Resource
    private RedisChatMemoryStore redisChatMemoryStore;

    @Resource
    private ChatHistoryService chatHistoryService;

    @Resource
    private ToolManager toolManager;

    @Resource
    private VipLimitService vipLimitService;

    @Resource
    private StreamingChatModelConfig streamingChatModelConfig;

    @Resource
    private ReasoningStreamingChatModelConfig reasoningStreamingChatModelConfig;

    /**
     * AI 服务实例缓存
     * 缓存策略：
     * - 最大缓存 1000 个实例
     * - 写入后 30 分钟过期
     * - 访问后 10 分钟过期
     */
    private final Cache<String, AiCodeGeneratorService> serviceCache = Caffeine.newBuilder()
            .maximumSize(1000) // 最大缓存 1000 个实例
            .expireAfterWrite(Duration.ofMinutes(30)) // 写入后 30 分钟过期
            .expireAfterAccess(Duration.ofMinutes(10)) // 访问后 10 分钟过期
            .removalListener((key, value, cause) -> log.debug("AI 服务实例被移除，缓存键: {}, 原因: {}", key, cause))
            .build();

    /**
     * 根据 appId 获取服务 (兼容旧逻辑)
     * @param appId 应用 ID
     * @return AI 代码生成服务实例
     */
    public AiCodeGeneratorService getAiCodeGeneratorService(long appId) {
        // 类似于 Map 的 getOrDefault 方法(有缓存直接取，没有就创建新的)
        return getAiCodeGeneratorService(appId, CodeGenTypeEnum.MULTI_FILE);
    }

    /**
     * 根据 appId 获取服务
     * @param appId 应用 ID
     * @param codeGenType 代码生成类型
     * @return AI 代码生成服务实例
     */
    public AiCodeGeneratorService getAiCodeGeneratorService(long appId, CodeGenTypeEnum codeGenType) {
        // 类似于 Map 的 getOrDefault 方法(有缓存直接取，没有就创建新的)
        String cacheKey = buildCacheKey(appId, codeGenType);
        return serviceCache.get(cacheKey, key -> createAiCodeGeneratorService(appId, codeGenType, null));
    }

    /**
     * 根据 appId 和用户信息获取服务（支持VIP限制）
     * @param appId 应用 ID
     * @param codeGenType 代码生成类型
     * @param user 用户信息
     * @return AI 代码生成服务实例
     */
    public AiCodeGeneratorService getAiCodeGeneratorService(long appId, CodeGenTypeEnum codeGenType, User user) {
        // 有用户信息，使用用户相关的缓存键
        String cacheKey = user != null ?
                buildCacheKeyWithUser(appId, codeGenType, user.getId()) :
                buildCacheKey(appId, codeGenType);
        return serviceCache.get(cacheKey, key -> createAiCodeGeneratorService(appId, codeGenType, user));
    }

    /**
     * 根据 appId 创建服务
     * @param appId 应用 ID
     * @param codeGenType 代码生成类型
     * @param user 用户信息（可以为null）
     * @return AI 代码生成服务实例
     */
    private AiCodeGeneratorService createAiCodeGeneratorService(long appId, CodeGenTypeEnum codeGenType, User user) {
        log.info("创建新的 AI 服务实例，appId: {}, user: {}", appId, user != null ? user.getId() : "null");

        // 动态获取最大消息数量（根据用户VIP等级）
        int maxMessages = user != null ? vipLimitService.getMaxMessages(user) : vipLimitConfig.getVip().getMaxMessages();

        // 根据 appId 构建独立的对话记忆
        MessageWindowChatMemory chatMemory = MessageWindowChatMemory
                .builder()
                .id(appId)
                .chatMemoryStore(redisChatMemoryStore) // 使用 Redis 存储对话记忆
                .maxMessages(maxMessages) // 使用动态配置的消息数量
                .build();

        // 从数据库加载历史对话到内存
        int loadedCount = chatHistoryService.loadChatHistoryToMemory(appId, chatMemory, maxMessages);
        log.info("为应用 {} 加载了 {} 条历史对话，maxMessages: {}", appId, loadedCount, maxMessages);

        return switch (codeGenType) {
            // Vue 项目生成，使用工具调用和推理模型，使用推理模型
            case VUE_PROJECT -> {
                StreamingChatModel reasoningStreamingChatModel;
                if (user != null) {
                    // 有用户上下文时，使用基于用户角色的推理模型配置
                    reasoningStreamingChatModel = reasoningStreamingChatModelConfig.createReasoningStreamingChatModelForUser(user.getUserRole());
                    
                    // 添加日志记录用于验证tokens配置
                    VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(user.getUserRole());
                    log.info("创建推理模型 - 用户角色: {}, MaxTokens: {}, 用户ID: {}", 
                        user.getUserRole(), limits.getMaxTokens(), user.getId());
                } else {
                    // 🔧 没有用户上下文时，使用默认配置（Bean创建时）
                    reasoningStreamingChatModel = ApplicationContextProvider.getBean("reasoningStreamingChatModelPrototype", StreamingChatModel.class);
                    log.info("创建推理模型 - 使用默认配置（无用户上下文）");
                }
                
                yield AiServices.builder(AiCodeGeneratorService.class)
                        .streamingChatModel(reasoningStreamingChatModel)
                        .chatMemoryProvider(memoryId -> createDynamicChatMemory(memoryId, appId, user)) // 使用动态内存提供者
                        .tools((Object[]) toolManager.getAllTools())
                        // 处理幻觉调用不存在的工具的操作
                        .hallucinatedToolNameStrategy(toolExecutionRequest ->
                                ToolExecutionResultMessage.from(toolExecutionRequest,
                                        "Error: there is no tool called " + toolExecutionRequest.name())
                        )
                        .inputGuardrails(new PromptSafetyInputGuardrail()) // 添加输入护轨
                        // .outputGuardrails(new RetryOutputGuardrail()) // 添加输出护轨，为了流式输出，这里不使用
                        // .maxSequentialToolsInvocations(20) // 最多允许连续调用 20 次工具
                        .build();
            }
            // HTML 和 多文件生成，使用流式普通对话模型
            case HTML, MULTI_FILE -> {
                StreamingChatModel openAiStreamingChatModel;
                if (user != null) {
                    // 有用户上下文时，使用基于用户角色的流式模型配置
                    openAiStreamingChatModel = streamingChatModelConfig.createStreamingChatModelForUser(user.getUserRole());
                    
                    // 添加日志记录用于验证tokens配置
                    VipLimitConfig.UserLimits limits = vipLimitConfig.getLimitsByRole(user.getUserRole());
                    log.info("创建流式模型 - 用户角色: {}, MaxTokens: {}, 用户ID: {}", 
                        user.getUserRole(), limits.getMaxTokens(), user.getId());
                } else {
                    // 没有用户上下文时，使用默认配置（Bean创建时）
                    openAiStreamingChatModel = ApplicationContextProvider.getBean("streamingChatModelPrototype", StreamingChatModel.class);
                    log.info("创建流式模型 - 使用默认配置（无用户上下文）");
                }
                
                yield AiServices.builder(AiCodeGeneratorService.class)
                        .chatModel(chatModel)
                        .streamingChatModel(openAiStreamingChatModel)
                        .chatMemory(chatMemory) // 使用动态配置的chatMemory
                        .inputGuardrails(new PromptSafetyInputGuardrail()) // 添加输入护轨
                        // .outputGuardrails(new RetryOutputGuardrail()) // 添加输出护轨，为了流式输出，这里不使用
                        .build();
            }
        };
    }

    /**
     * 创建动态的ChatMemory，根据用户VIP等级调整maxMessages
     * @param memoryId 内存ID
     * @param appId 应用ID
     * @param user 用户信息
     * @return 动态配置的ChatMemory
     */
    private MessageWindowChatMemory createDynamicChatMemory(Object memoryId, Long appId, User user) {
        try {
            // 获取动态的最大消息数量
            int maxMessages = user != null ? vipLimitService.getMaxMessages(user) : 20;

            MessageWindowChatMemory dynamicChatMemory = MessageWindowChatMemory
                    .builder()
                    .id(memoryId)
                    .chatMemoryStore(redisChatMemoryStore)
                    .maxMessages(maxMessages) // 动态设置
                    .build();

            // 从数据库加载历史对话到内存
            chatHistoryService.loadChatHistoryToMemory(appId, dynamicChatMemory, maxMessages);

            log.info("创建动态ChatMemory，appId: {}, memoryId: {}, maxMessages: {}", appId, memoryId, maxMessages);
            return dynamicChatMemory;
        } catch (Exception e) {
            log.warn("创建动态ChatMemory失败，使用默认配置，error: {}", e.getMessage());
            // 失败时使用默认配置
            return MessageWindowChatMemory
                    .builder()
                    .id(memoryId)
                    .chatMemoryStore(redisChatMemoryStore)
                    .maxMessages(vipLimitConfig.getVip().getMaxMessages()) // 默认值
                    .build();
        }
    }

    /**
     * 创建 AI 代码生成服务
     *
     * @return AI 代码生成服务实例
     */
    @Bean
    public AiCodeGeneratorService aiCodeGeneratorService() {
        // 修改为使用创建每个appId创建独立的service（一段对话一个service）
        return getAiCodeGeneratorService(0L);
    }

    /**
     * 获取用于生成应用名称的独立AI服务实例
     * 该服务不加载历史对话，避免上下文污染
     * @return 独立的AI代码生成服务实例
     */
    public AiCodeGeneratorService getAppNameGeneratorService() {
        // 使用特殊的缓存键，避免与普通服务混淆
        String cacheKey = "APP_NAME_GENERATOR";
        return serviceCache.get(cacheKey, key -> createAppNameGeneratorService());
    }

    /**
     * 创建专门用于生成应用名称的AI服务实例
     * 不加载历史对话，保持上下文干净
     * @return AI代码生成服务实例
     */
    private AiCodeGeneratorService createAppNameGeneratorService() {
        log.info("创建独立的应用名称生成AI服务实例");

        // 创建一个全新的对话记忆，不从数据库加载历史记录
        MessageWindowChatMemory cleanChatMemory = MessageWindowChatMemory
                .builder()
                .id(-1L) // 使用特殊ID，确保不会与其他对话混淆
                .maxMessages(2) // 只保留最少的消息，专注于当前请求
                .build();

        // 使用路由模型（简化生成应用名称）
        ChatModel routingChatModel = ApplicationContextProvider.getBean("routingChatModelPrototype", ChatModel.class);
        return AiServices.builder(AiCodeGeneratorService.class)
                .chatModel(routingChatModel)
                .chatMemory(cleanChatMemory)
                .build();
    }

    /**
     * 构建缓存键
     * @param appId 应用 ID
     * @param codeGenType 代码生成类型
     * @return 缓存键
     */
    private String buildCacheKey(Long appId, CodeGenTypeEnum codeGenType) {
        return appId + "_" + codeGenType.getValue();
    }

    /**
     * 构建包含用户信息的缓存键
     * @param appId 应用 ID
     * @param codeGenType 代码生成类型
     * @param userId 用户ID
     * @return 缓存键
     */
    private String buildCacheKeyWithUser(Long appId, CodeGenTypeEnum codeGenType, Long userId) {
        return appId + "_" + codeGenType.getValue() + "_user_" + userId;
    }
}
